package com.liu.analysis;


import java.util.ArrayList;
import java.util.Arrays;
import java.util.EmptyStackException;
import java.util.List;
import java.util.Stack;

import com.liu.system.Error;
import com.liu.system.MyException;
import com.liu.system.Varibles;

/*
 * 用于进行表达式计算
 *  创建于2017.3.9
 * @author lyq
 * */
public class Calculation {
	
	/*
	 * 将中缀表达式转换为后缀表达式
	 * @param str 需要转化的字符串
	 * @return 返回后缀表达式
	 * @exception 使用了未经初始化的变量
	 * */
	private static List<String> changeForm(List<String> list) throws MyException{
		//用来保存运算符号
		Stack<String> symbolStack = new Stack<String>();
		//用来存储数字及最后的后缀表达式
		List<String> result = new ArrayList<String>();
		//用来存储扫描到的字符串的下标位置
		int index = 0;
		
		while(index < list.size()){
			String str = list.get(index);
			//遇到整型数字直接添加到后缀表达式中
			if(str.matches("[\\d]+")){
				result.add(str);
			}
			//遇到浮点数直接添加到后缀表达式中
			else if(str.matches("[\\d]+\\.[\\d]+")){
				result.add(str);
			}
			//遇到变量名去变量名集合中查找有无该变量,有则入栈，无则报错
			else if(str.matches("[a-zA-Z]+[a-zA-Z0-9]*")){
				if (SentenceAnalysis.isKeyWord(str)) {
					throw new MyException(Error.NAME_WITH_KEYWORD);
				}
				if (Varibles.variblesMap.containsKey(str)) {
					String value = Varibles.variblesMap.get(str);
					result.add(value);
				}
				//使用了未经初始化的变量进行运算
				else{
					throw new MyException(Error.NO_THIS_VARIBLE);
				}
			}
			//+号
			else if(str.equals("+")){
				//符号栈为空则直接入栈
				if(symbolStack.empty()){
					symbolStack.push(str);
				}else{
					boolean mark = true;
					while(mark && !symbolStack.empty()){
						String top = symbolStack.peek();
						if(top.equals("+")||top.equals("-")
							||top.equals("*")||top.equals("/")
							){
							result.add(symbolStack.pop());
						}else {
							mark = false;
						}
					}
					symbolStack.push(str);
				}
			}
			//-号
			else if(str.equals("-")){
				//符号栈为空则直接入栈
				if(symbolStack.empty()){
					symbolStack.push(str);
				}else{
					boolean mark = true;
					while(mark && !symbolStack.empty()){
						String top = symbolStack.peek();
						if(top.equals("+")||top.equals("-")
							||top.equals("*")||top.equals("/")
							){
							result.add(symbolStack.pop());
						}else {
							mark = false;
						}
					}
					symbolStack.push(str);
				}
			}
			//*号
			else if(str.equals("*")){
				//符号栈为空则直接入栈
				if(symbolStack.empty()){
					symbolStack.push(str);
				}else{
					boolean mark = true;
					while(mark && !symbolStack.empty()){
						String top = symbolStack.peek();
						if(top.equals("*") || top.equals("/")
							){
							result.add(symbolStack.pop());
						}else {
							mark = false;
						}
					}
					symbolStack.push(str);
				}		
			}
			//除号
			else if(str.equals("/")){
				//符号栈为空则直接入栈
				if(symbolStack.empty()){
					symbolStack.push(str);
				}else{
					boolean mark = true;
					while(mark && !symbolStack.empty()){
						String top = symbolStack.peek();
						if(top.equals("*")||top.equals("/")
							){
							result.add(symbolStack.pop());
						}else {
							mark = false;
						}
					}
					symbolStack.push(str);
				}
			}
			//左括号直接入栈
			else if(str.equals("(")){
				symbolStack.push(str);
			}
			//右括号
			else if (str.equals(")")) {
				boolean mark = true;
				while(mark && !symbolStack.empty()){
					//遇到左括号停止弹出栈顶元素，左括号不输出
					if(symbolStack.peek().equals("(")){
						symbolStack.pop();
						mark = false;
					}
					//非左括号则弹出栈顶元素并将其加入后缀表达式
					else {
						result.add(symbolStack.pop());
					}
				}
			}
			//找不到该类型的符号
			else {
				throw new MyException(Error.NO_THIS_TYPE);
			}
			index++;
		}
		while(!symbolStack.empty()){
			result.add(symbolStack.pop());
		}
		return result;
	}
	
	/*
	 * 后缀表达式求值
	 * @param list 后缀表达式
	 * @exception MyException 除数为0或者是表达式形式错误时都有可能抛出，具体情况参照异常提示信息
	 * @exception EmptyStackException 表达式形式错误
	 * */
	private static String evaluation(List<String> list) throws MyException,EmptyStackException{
		Stack<String> stack = new Stack<String>();
		//扫描后缀表达式
		for(int i = 0;i < list.size();i++){
			String str = list.get(i);
			//遇到操作数直接进栈
			if(str.matches("[\\d]+") || str.matches("[\\d]+\\.[\\d]+")){
				stack.push(str);
			}else{
				String snumber1 = stack.pop();
				String snumber2 = stack.pop();
				//全是整型.则都转换为整型
				if(snumber1.matches("[\\d]+") && snumber2.matches("[\\d]+")){
					int number1 = Integer.parseInt(snumber1); 
					int number2 = Integer.parseInt(snumber2);
					switch (str) {
					case "+":
						stack.push(String.valueOf(number2 + number1));
						break;
					case "-":
						stack.push(String.valueOf(number2 - number1));				
						break;
					case "*":
						stack.push(String.valueOf(number2 * number1));						
						break;
					case "/":
						if(number1 == 0){
							throw new MyException(Error.DIVIDED_BY_ZERO);
						}else{
							stack.push(String.valueOf(number2 / number1));							
						}				
						break;
					}
				}
				//有浮点型则都转换为浮点型
				else{
					double number1 = Double.parseDouble(snumber1);
					double number2 = Double.parseDouble(snumber2);
					switch (str) {
					case "+":
						stack.push(String.valueOf(number2 + number1));
						break;
					case "-":
						stack.push(String.valueOf(number2 - number1));				
						break;
					case "*":
						stack.push(String.valueOf(number2 * number1));						
						break;
					case "/":
						if(number1 == 0){
							throw new MyException(Error.DIVIDED_BY_ZERO);
						}else{
							stack.push(String.valueOf(number2 / number1));							
						}				
						break;
					}
				}			
			}
		}
		if(stack.size() > 1){
			throw new MyException(Error.WRONG_FORMAT_OF_EXPRESSION);
		}
		return stack.pop();
	}
	
	/*
	 * 对外的计算接口
	 * @param list 需要进行计算的字符串
	 * @return 返回计算结果
	 */
	public static String forResult(List<String> list) throws MyException,EmptyStackException{
		List<String> result = changeForm(list);
		return evaluation(result);
	}
	
	public static void main(String[] args) throws MyException {
		List<String> list = Arrays.asList("2","*","2","-","2","/","2");
		List<String> result = changeForm(list);
		for(String s:result){
			System.out.print(s+" ");
		}
	}
}
